using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using SLProxy;
using libsecondlife;
using libsecondlife.Packets;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;

namespace StickyChat
{
    public class StickySensor : UserControl, StickIn
    {
        private StickyServices loader;
        private string myName;
        private TextBox sensorOutput;
        private CheckBox sensorActive;
        private ListBox sensorList;
        private TextBoxWriter sensorOutputWriter;
        private BackgroundWorker worker;

        public StickySensor(StickyServices p)
        {
            loader = p;
            myName = "Sensor";
            InitializeComponent();
            sensorOutputWriter = new TextBoxWriter(sensorOutput);
            worker = new BackgroundWorker();
            worker.DoWork += ObjectUpdateWork;
        }

        private void InitializeComponent()
        {
            this.sensorOutput = new System.Windows.Forms.TextBox();
            this.sensorActive = new System.Windows.Forms.CheckBox();
            this.sensorList = new System.Windows.Forms.ListBox();
            this.SuspendLayout();
            // 
            // sensorOutput
            // 
            this.sensorOutput.Location = new System.Drawing.Point(3, 222);
            this.sensorOutput.Multiline = true;
            this.sensorOutput.Name = "sensorOutput";
            this.sensorOutput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.sensorOutput.Size = new System.Drawing.Size(461, 144);
            this.sensorOutput.TabIndex = 0;
            // 
            // sensorActive
            // 
            this.sensorActive.AutoSize = true;
            this.sensorActive.Location = new System.Drawing.Point(3, 8);
            this.sensorActive.Name = "sensorActive";
            this.sensorActive.Size = new System.Drawing.Size(56, 17);
            this.sensorActive.TabIndex = 1;
            this.sensorActive.Text = "Active";
            this.sensorActive.UseVisualStyleBackColor = true;
            this.sensorActive.CheckedChanged += new System.EventHandler(this.sensorActive_CheckedChanged);
            // 
            // sensorList
            // 
            this.sensorList.FormattingEnabled = true;
            this.sensorList.Location = new System.Drawing.Point(3, 31);
            this.sensorList.Name = "sensorList";
            this.sensorList.Size = new System.Drawing.Size(458, 186);
            this.sensorList.TabIndex = 2;
            this.sensorList.SelectedIndexChanged += new System.EventHandler(this.sensorList_SelectedIndexChanged);
            // 
            // StickySensor
            // 
            this.Controls.Add(this.sensorList);
            this.Controls.Add(this.sensorActive);
            this.Controls.Add(this.sensorOutput);
            this.Name = "StickySensor";
            this.Size = new System.Drawing.Size(464, 369);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #region StickIn Members

        public string name
        {
            get { return myName; }
        }

        public void start()
        {
            //loader.proxy.AddDelegate(PacketType.ViewerEffect, Direction.Incoming, ViewerEffect);
        }

        public void stop()
        {
            loader.proxy.RemoveDelegate(PacketType.ObjectUpdate, Direction.Incoming, ObjectUpdated);
        }
        #endregion StickIn Members

        private Packet ViewerEffect(Packet packet, IPEndPoint sim)
        {
            ViewerEffectPacket effect = (ViewerEffectPacket)packet;
            foreach (ViewerEffectPacket.EffectBlock block in effect.Effect)
            {
                if (block.Type == 7)
                {
                    sensorOutputWriter.WriteLine(block.ToString());
                    sensorOutputWriter.WriteLine("TEST:" + new LLVector3d(block.TypeData, 32).ToString());
                }
            }
            //new Thread(delegate() { ViewerEffectWork(packet); }).Start();
            return packet;
        }

        private void ViewerEffectWork(Packet packet)
        {
            ViewerEffectPacket effect = (ViewerEffectPacket)packet;
            foreach (ViewerEffectPacket.EffectBlock block in effect.Effect)
            {
                if (block.Type == 7)
                {
                    sensorOutputWriter.WriteLine(block.ToString());
                }
            }
        }

        private Packet ObjectUpdated(Packet packet, IPEndPoint sim)
        {
            // deconstruct the packet
            ObjectUpdatePacket update = (ObjectUpdatePacket)packet;
            foreach (ObjectUpdatePacket.ObjectDataBlock obj in update.ObjectData)
            {
                if (obj.PCode == (byte)(0x20 | 15)) // AVATAR | LEGACY
                {
                    if (obj.ObjectData.Length == 76)
                    {
                        string name = " ";
                        for (Match m = Regex.Match(Helpers.FieldToUTF8String(obj.NameValue), @"(\S*) \S* \S* \S* (.*)\n?"); m.Success; m = m.NextMatch())
                        {
                            if (m.Groups[1].Value == "FirstName")
                            {
                                name = m.Groups[2].Value + name;
                            }
                            else if (m.Groups[1].Value == "LastName")
                            {
                                name += m.Groups[2].Value;
                            }
                        }
                        LLVector3 pos = new LLVector3(obj.ObjectData, 16);
                        sensorOutputWriter.WriteLine(name + " at " + pos.ToString());
                    }
                    else
                    {
                        sensorOutputWriter.WriteLine("Unhandled block length: " + obj.ObjectData.Length);
                    }
                    //lock (sensorList)
                    //{
                    if(!sensorList.Items.Contains(obj.FullID))
                        sensorList.Items.Add(obj.FullID);
                    //}
                }
            }
            //new Thread(delegate() { ObjectUpdateWork(packet); }).Start();/**/
            //worker.RunWorkerAsync(packet);
            return packet;
        }

        private void ObjectUpdateWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                // deconstruct the packet
                ObjectUpdatePacket update = (ObjectUpdatePacket)e.Argument;
                foreach (ObjectUpdatePacket.ObjectDataBlock obj in update.ObjectData)
                {
                    if (obj.PCode == (byte)(0x20 | 15)) // AVATAR | LEGACY
                    {
                        if (obj.ObjectData.Length == 76)
                        {
                            string name = " ";
                            for (Match m = Regex.Match(Helpers.FieldToUTF8String(obj.NameValue), @"(\S*) \S* \S* \S* (.*)\n?"); m.Success; m = m.NextMatch())
                            {
                                if (m.Groups[1].Value == "FirstName")
                                {
                                    name = m.Groups[2].Value + name;
                                }
                                else if (m.Groups[1].Value == "LastName")
                                {
                                    name += m.Groups[2].Value;
                                }
                            }
                            LLVector3 pos = new LLVector3(obj.ObjectData, 16);
                            sensorOutputWriter.WriteLine(name + " at " + pos.ToString());
                        }
                        else
                        {
                            sensorOutputWriter.WriteLine("Unhandled block length: " + obj.ObjectData.Length);
                        }
                        sensorList.Items.Add(obj.FullID);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
        }

        private Packet ObjectUpdatedTerse(Packet packet, IPEndPoint sim)
        {
            // deconstruct the packet
            ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet;
            foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock obj in update.ObjectData)
            {
                if (obj.Data[5] != 0) // AVATAR | LEGACY
                {
                    LLVector3 pos=new LLVector3(obj.Data, 22);
                    sensorOutputWriter.WriteLine("Terse at " + pos.ToString());
                }
            }

            return update;
        }

        private void sensorActive_CheckedChanged(object sender, EventArgs e)
        {
            if (loader.proxy != null)
            {
                if (sensorActive.Checked)
                {
                    loader.proxy.AddDelegate(PacketType.ObjectUpdate, Direction.Incoming, ObjectUpdated);
                    //loader.proxy.AddDelegate(PacketType.ImprovedTerseObjectUpdate, Direction.Incoming, ObjectUpdatedTerse);
                }
                else
                {
                    loader.proxy.RemoveDelegate(PacketType.ObjectUpdate, Direction.Incoming, ObjectUpdated);
                    //loader.proxy.RemoveDelegate(PacketType.ImprovedTerseObjectUpdate, Direction.Incoming, ObjectUpdatedTerse);
                }
            }
        }

        private void sensorList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (loader.proxy != null)
            {
                ViewerEffectPacket effect = new ViewerEffectPacket();
                effect.AgentData = new ViewerEffectPacket.AgentDataBlock();
                effect.AgentData.AgentID = loader.AgentID;
                effect.AgentData.SessionID = loader.SessionID;
                effect.Effect = new ViewerEffectPacket.EffectBlock[2];
                effect.Effect[0] = new ViewerEffectPacket.EffectBlock();
                effect.Effect[0].AgentID = loader.AgentID;
                effect.Effect[0].Color = new byte[4];
                effect.Effect[0].Duration = 5.0f;
                effect.Effect[0].ID = LLUUID.Random();
                effect.Effect[0].Type = 7;
                effect.Effect[0].TypeData = new byte[56];
                int i = 0;
                foreach (byte b in loader.AgentID.GetBytes())
                {
                    effect.Effect[0].TypeData[i++] = b;
                }
                LLUUID target = (LLUUID)sensorList.SelectedItem;
                foreach (byte b in target.GetBytes())
                {
                    effect.Effect[0].TypeData[i++] = b;
                }
                effect.Effect[1] = new ViewerEffectPacket.EffectBlock();
                effect.Effect[1].AgentID = loader.AgentID;
                effect.Effect[1].Color = new byte[4];
                effect.Effect[1].Duration = 5.0f;
                effect.Effect[1].ID = LLUUID.Random();
                effect.Effect[1].Type = 15;
                effect.Effect[1].TypeData = new byte[57];
                i = 0;
                foreach (byte b in loader.AgentID.GetBytes())
                {
                    effect.Effect[1].TypeData[i++] = b;
                }
                foreach (byte b in target.GetBytes())
                {
                    effect.Effect[1].TypeData[i++] = b;
                }
                effect.Effect[1].TypeData[56] = 1;
                loader.proxy.InjectPacket(effect, Direction.Incoming);
            }
        }
    }
}